package com.asr.testclient.controller;

import com.asr.testclient.model.ConnectionState;
import com.asr.testclient.model.ServerMessage;
import com.asr.testclient.model.SubmissionState;
import com.asr.testclient.service.ASRWebSocketClient;
import com.asr.testclient.service.AudioFileHandler;
import com.asr.testclient.service.MessageParser;
import com.asr.testclient.view.MainFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * 主控制器
 * 协调GUI和服务层之间的交互
 */
public class MainController {
    private static final Logger logger = LoggerFactory.getLogger(MainController.class);
    
    private final MainFrame view;
    private ASRWebSocketClient webSocketClient;
    private final AudioFileHandler audioFileHandler;
    private final MessageParser messageParser;
    
    private ConnectionState connectionState;
    private SubmissionState submissionState;

    /**
     * 构造函数
     * @param view 主窗口视图
     */
    public MainController(MainFrame view) {
        this.view = view;
        this.audioFileHandler = new AudioFileHandler();
        this.messageParser = new MessageParser();
        this.connectionState = ConnectionState.DISCONNECTED;
        this.submissionState = SubmissionState.IDLE;
        
        logger.info("MainController initialized");
    }

    /**
     * 处理连接按钮点击事件
     */
    public void handleConnect() {
        logger.info("handleConnect called");
        
        // 验证服务器地址
        String serverAddress = view.getConnectionPanel().getServerAddress();
        if (serverAddress.isEmpty()) {
            view.getConnectionPanel().setConnectionStatus("错误: 服务器地址不能为空");
            logger.warn("Server address is empty");
            return;
        }
        
        if (!validateServerAddress(serverAddress)) {
            view.getConnectionPanel().setConnectionStatus("错误: 请输入有效的服务器地址");
            logger.warn("Invalid server address format: {}", serverAddress);
            return;
        }
        
        // 验证端口号
        int port = view.getConnectionPanel().getPort();
        if (port == -1) {
            view.getConnectionPanel().setConnectionStatus("错误: 端口号必须是数字");
            logger.warn("Port is not a valid number");
            return;
        }
        
        if (!validatePort(port)) {
            view.getConnectionPanel().setConnectionStatus("错误: 端口号必须在1-65535之间");
            logger.warn("Port number out of range: {}", port);
            return;
        }
        
        try {
            // 构建WebSocket URI
            String wsUri = String.format("ws://%s:%d", serverAddress, port);
            URI serverUri = new URI(wsUri);
            
            logger.info("Attempting to connect to: {}", wsUri);
            
            // 更新状态
            connectionState = ConnectionState.CONNECTING;
            view.getConnectionPanel().setConnectionStatus("连接中...");
            view.getConnectionPanel().setConnected(false);
            
            // 创建并连接WebSocket客户端
            webSocketClient = new ASRWebSocketClient(serverUri, this);
            webSocketClient.connect();
            
        } catch (URISyntaxException e) {
            logger.error("Invalid URI syntax", e);
            connectionState = ConnectionState.ERROR;
            view.getConnectionPanel().setConnectionStatus("错误: 无效的服务器地址格式");
            JOptionPane.showMessageDialog(
                view,
                "无法构建连接地址，请检查服务器地址和端口格式",
                "连接错误",
                JOptionPane.ERROR_MESSAGE
            );
        } catch (Exception e) {
            logger.error("Failed to connect", e);
            connectionState = ConnectionState.ERROR;
            String errorMsg = e.getMessage() != null ? e.getMessage() : "未知错误";
            view.getConnectionPanel().setConnectionStatus("连接失败: " + errorMsg);
            JOptionPane.showMessageDialog(
                view,
                "连接失败: " + errorMsg + "\n请检查服务器地址、端口和网络连接",
                "连接错误",
                JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * 处理断开按钮点击事件
     */
    public void handleDisconnect() {
        logger.info("handleDisconnect called");
        
        if (webSocketClient != null && webSocketClient.isOpen()) {
            try {
                webSocketClient.close();
                logger.info("WebSocket connection closed by user");
            } catch (Exception e) {
                logger.error("Error closing WebSocket connection", e);
            }
        }
        
        // 重置状态
        connectionState = ConnectionState.DISCONNECTED;
        submissionState = SubmissionState.IDLE;
        
        // 更新UI
        view.getConnectionPanel().setConnectionStatus("未连接");
        view.getConnectionPanel().setConnected(false);
        view.getInputPanel().setSubmitEnabled(false);
    }

    /**
     * 处理选择文件按钮点击事件
     */
    public void handleSelectFile() {
        logger.info("handleSelectFile called");
        
        try {
            // 打开文件选择对话框
            File selectedFile = audioFileHandler.selectAudioFile(view);
            
            if (selectedFile == null) {
                logger.debug("No file selected");
                return;
            }
            
            // 验证文件格式
            if (!audioFileHandler.validateFileFormat(selectedFile)) {
                logger.warn("Invalid file format: {}", selectedFile.getName());
                JOptionPane.showMessageDialog(
                    view,
                    "请选择WAV或PCM格式的音频文件",
                    "文件格式错误",
                    JOptionPane.WARNING_MESSAGE
                );
                return;
            }
            
            // 验证文件大小
            if (!audioFileHandler.validateFileSize(selectedFile)) {
                logger.warn("File size exceeds limit: {}", selectedFile.getName());
                JOptionPane.showMessageDialog(
                    view,
                    "文件大小超过10MB限制\n当前文件大小: " + 
                    String.format("%.2f MB", selectedFile.length() / (1024.0 * 1024.0)),
                    "文件过大",
                    JOptionPane.WARNING_MESSAGE
                );
                return;
            }
            
            // 读取文件内容
            byte[] fileData = audioFileHandler.readAudioFile(selectedFile);
            
            if (fileData == null || fileData.length == 0) {
                logger.warn("File is empty: {}", selectedFile.getName());
                JOptionPane.showMessageDialog(
                    view,
                    "文件为空或无法读取",
                    "文件读取错误",
                    JOptionPane.ERROR_MESSAGE
                );
                return;
            }
            
            // 编码为Base64
            String base64Data = audioFileHandler.encodeToBase64(fileData);
            
            if (base64Data.isEmpty()) {
                logger.error("Base64 encoding failed for file: {}", selectedFile.getName());
                JOptionPane.showMessageDialog(
                    view,
                    "文件编码失败",
                    "编码错误",
                    JOptionPane.ERROR_MESSAGE
                );
                return;
            }
            
            // 填充到文本框
            view.getInputPanel().setBase64Data(base64Data);
            
            logger.info("File loaded successfully: {}, size: {} bytes", 
                       selectedFile.getName(), fileData.length);
            view.getResultPanel().setStatus("文件已加载: " + selectedFile.getName() + 
                " (" + String.format("%.2f KB", fileData.length / 1024.0) + ")");
            
        } catch (java.io.FileNotFoundException e) {
            logger.error("File not found", e);
            JOptionPane.showMessageDialog(
                view,
                "文件不存在或已被删除",
                "文件未找到",
                JOptionPane.ERROR_MESSAGE
            );
        } catch (java.io.IOException e) {
            logger.error("IO error reading file", e);
            String errorMsg = e.getMessage() != null ? e.getMessage() : "未知IO错误";
            JOptionPane.showMessageDialog(
                view,
                "无法读取文件: " + errorMsg + "\n请检查文件权限和磁盘状态",
                "文件读取错误",
                JOptionPane.ERROR_MESSAGE
            );
        } catch (Exception e) {
            logger.error("Unexpected error loading file", e);
            String errorMsg = e.getMessage() != null ? e.getMessage() : "未知错误";
            JOptionPane.showMessageDialog(
                view,
                "加载文件时发生错误: " + errorMsg,
                "错误",
                JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * 处理提交按钮点击事件
     */
    public void handleSubmit() {
        logger.info("handleSubmit called");
        
        // 检查连接状态
        if (connectionState != ConnectionState.CONNECTED || webSocketClient == null || !webSocketClient.isOpen()) {
            logger.warn("Cannot submit: not connected to server");
            view.getResultPanel().appendError("未连接到服务器，请先建立连接");
            JOptionPane.showMessageDialog(
                view,
                "请先连接到ASR服务器",
                "未连接",
                JOptionPane.WARNING_MESSAGE
            );
            return;
        }
        
        // 获取Base64数据
        String base64Data = view.getInputPanel().getBase64Data();
        
        if (base64Data == null || base64Data.trim().isEmpty()) {
            logger.warn("Cannot submit: no audio data");
            view.getResultPanel().appendError("请输入或选择音频数据");
            JOptionPane.showMessageDialog(
                view,
                "请先输入Base64音频数据或选择音频文件",
                "无数据",
                JOptionPane.WARNING_MESSAGE
            );
            return;
        }
        
        try {
            // 更新状态
            submissionState = SubmissionState.SENDING;
            view.getResultPanel().setStatus("正在发送...");
            
            // 直接发送音频数据（实时识别模式）
            // 数据应该已经是完整的音频文件格式（WAV/WebM等）
            webSocketClient.sendAudioChunk(base64Data);
            
            // 发送结束音频消息
            webSocketClient.sendEndAudio();
            
            // 更新状态
            submissionState = SubmissionState.WAITING;
            view.getResultPanel().setStatus("已发送，等待结果...");
            
            logger.info("Audio chunk submitted successfully, data length: {}", base64Data.length());
            
        } catch (IllegalStateException e) {
            logger.error("WebSocket not in valid state", e);
            submissionState = SubmissionState.IDLE;
            view.getResultPanel().appendError("连接状态异常，请重新连接");
            JOptionPane.showMessageDialog(
                view,
                "WebSocket连接状态异常，请断开后重新连接",
                "连接错误",
                JOptionPane.ERROR_MESSAGE
            );
        } catch (Exception e) {
            logger.error("Failed to submit audio data", e);
            submissionState = SubmissionState.IDLE;
            String errorMsg = e.getMessage() != null ? e.getMessage() : "未知错误";
            view.getResultPanel().appendError("提交失败: " + errorMsg);
            JOptionPane.showMessageDialog(
                view,
                "提交音频数据失败: " + errorMsg + "\n请检查网络连接",
                "提交错误",
                JOptionPane.ERROR_MESSAGE
            );
        }
    }

    /**
     * 处理清空输入按钮点击事件
     */
    public void handleClearInput() {
        logger.info("handleClearInput called");
        view.getInputPanel().clearInput();
    }

    /**
     * 处理清空结果按钮点击事件
     */
    public void handleClearResult() {
        logger.info("handleClearResult called");
        view.getResultPanel().clearResults();
    }

    /**
     * WebSocket连接建立回调
     */
    public void onConnectionEstablished() {
        logger.info("onConnectionEstablished callback");
        
        connectionState = ConnectionState.CONNECTED;
        view.getConnectionPanel().setConnectionStatus("已连接");
        view.getConnectionPanel().setConnected(true);
        
        // 如果有数据，启用提交按钮
        if (!view.getInputPanel().getBase64Data().isEmpty()) {
            view.getInputPanel().setSubmitEnabled(true);
        }
    }

    /**
     * WebSocket连接失败回调
     * @param error 错误信息
     */
    public void onConnectionFailed(String error) {
        logger.error("onConnectionFailed callback: {}", error);
        
        connectionState = ConnectionState.ERROR;
        
        // 提供用户友好的错误消息
        String userFriendlyError = error;
        if (error.contains("Connection refused")) {
            userFriendlyError = "连接被拒绝，请检查服务器是否运行";
        } else if (error.contains("timeout")) {
            userFriendlyError = "连接超时，请检查网络和服务器地址";
        } else if (error.contains("Unknown host")) {
            userFriendlyError = "无法解析服务器地址";
        }
        
        view.getConnectionPanel().setConnectionStatus("连接失败: " + userFriendlyError);
        view.getConnectionPanel().setConnected(false);
        view.getInputPanel().setSubmitEnabled(false);
    }

    /**
     * WebSocket接收消息回调
     * @param message 接收到的消息
     */
    public void onMessageReceived(String message) {
        logger.info("onMessageReceived callback");
        logger.debug("Message content: {}", message);
        
        try {
            // 解析消息
            ServerMessage serverMessage = messageParser.parse(message);
            
            if (serverMessage == null) {
                logger.warn("Failed to parse server message");
                view.getResultPanel().appendError("收到无效的服务器响应");
                view.getResultPanel().setStatus("原始消息: " + 
                    (message.length() > 100 ? message.substring(0, 100) + "..." : message));
                return;
            }
            
            String messageType = serverMessage.getType();
            logger.debug("Message type: {}", messageType);
            
            // 根据消息类型处理
            if ("recognition_result".equals(messageType) || "file_recognition_result".equals(messageType)) {
                // 提取识别结果（支持实时模式和文件模式）
                String recognitionResult = messageParser.extractRecognitionResult(serverMessage);
                
                if (recognitionResult != null && !recognitionResult.trim().isEmpty()) {
                    view.getResultPanel().appendResult(recognitionResult);
                    logger.info("Recognition result displayed: {}", recognitionResult);
                } else {
                    logger.warn("Recognition result is empty");
                    view.getResultPanel().appendError("服务器返回的识别结果为空");
                }
                
                // 更新提交状态并清除状态消息
                submissionState = SubmissionState.COMPLETED;
                view.getResultPanel().setStatus("");
                
            } else if ("recognition_complete".equals(messageType)) {
                // 实时识别完成消息
                logger.info("Recognition complete message received");
                view.getResultPanel().setStatus("识别完成");
                submissionState = SubmissionState.COMPLETED;
                
            } else if ("mode_selected".equals(messageType)) {
                // 模式选择确认消息
                logger.info("Mode selected confirmation received");
                
            } else if ("error".equals(messageType)) {
                // 提取错误信息
                String errorMessage = messageParser.extractErrorMessage(serverMessage);
                
                if (errorMessage != null && !errorMessage.trim().isEmpty()) {
                    view.getResultPanel().appendError("服务器错误: " + errorMessage);
                    logger.info("Error message displayed: {}", errorMessage);
                } else {
                    logger.warn("Error message is empty");
                    view.getResultPanel().appendError("服务器返回错误但未提供详细信息");
                }
                
                // 更新提交状态并清除状态消息
                submissionState = SubmissionState.COMPLETED;
                view.getResultPanel().setStatus("");
                
            } else {
                // 未知消息类型
                logger.warn("Unknown message type: {}", messageType);
                view.getResultPanel().appendError("收到未知消息类型: " + messageType);
                view.getResultPanel().setStatus("原始消息: " + 
                    (message.length() > 100 ? message.substring(0, 100) + "..." : message));
            }
            
        } catch (com.google.gson.JsonSyntaxException e) {
            logger.error("JSON parsing error", e);
            view.getResultPanel().appendError("服务器响应格式错误，无法解析JSON");
            view.getResultPanel().setStatus("原始消息: " + 
                (message.length() > 100 ? message.substring(0, 100) + "..." : message));
        } catch (Exception e) {
            logger.error("Unexpected error processing received message", e);
            String errorMsg = e.getMessage() != null ? e.getMessage() : "未知错误";
            view.getResultPanel().appendError("处理服务器响应时出错: " + errorMsg);
        }
    }

    /**
     * WebSocket连接关闭回调
     */
    public void onConnectionClosed() {
        logger.info("onConnectionClosed callback");
        
        connectionState = ConnectionState.DISCONNECTED;
        view.getConnectionPanel().setConnectionStatus("连接已断开");
        view.getConnectionPanel().setConnected(false);
        view.getInputPanel().setSubmitEnabled(false);
    }

    /**
     * 验证服务器地址格式
     * @param address 服务器地址
     * @return true如果有效，false如果无效
     */
    private boolean validateServerAddress(String address) {
        if (address == null || address.trim().isEmpty()) {
            logger.warn("Server address is empty");
            return false;
        }
        
        // 验证不包含空格
        if (address.contains(" ")) {
            logger.warn("Server address contains spaces");
            return false;
        }
        
        // 验证不包含非法字符
        if (address.contains("\\") || address.contains("\"") || address.contains("'")) {
            logger.warn("Server address contains illegal characters");
            return false;
        }
        
        // 验证基本格式（域名或IP地址）
        // 允许字母、数字、点、连字符
        if (!address.matches("^[a-zA-Z0-9.-]+$")) {
            logger.warn("Server address contains invalid characters");
            return false;
        }
        
        return true;
    }

    /**
     * 验证端口号范围
     * @param port 端口号
     * @return true如果有效（1-65535），false如果无效
     */
    private boolean validatePort(int port) {
        boolean isValid = port >= 1 && port <= 65535;
        
        if (!isValid) {
            logger.warn("Invalid port number: {}", port);
        }
        
        return isValid;
    }
}
